# encoding=utf-8

from typing import Optional, Set, Coroutine, Callable, Sequence, Mapping, Deque

import asyncio
import logging
import collections

logger = logging.getLogger(__name__)


async def maybe_await(value):
    if hasattr(value, '__await__'):
        return await value
    else:
        return value


def get_loop() -> asyncio.AbstractEventLoop:
    try:
        # Python 3.7+
        return asyncio.get_running_loop()  # type: ignore
    except (AttributeError, RuntimeError):
        return asyncio.get_event_loop()


def create_task(coro, loop=None) -> asyncio.Task:
    loop = loop or get_loop()
    return loop.create_task(coro)


def all_tasks(loop=None, is_raise=False):
    loop = loop or get_loop()
    try:
        # Python 3.7+
        return asyncio.all_tasks(loop=loop)
    except AttributeError:
        return asyncio.Task.all_tasks(loop=loop)


def current_task(loop=None, is_raise=False):
    loop = loop or get_loop()
    try:
        try:
            # Python 3.7+
            return asyncio.current_task(loop=loop)
        except AttributeError:
            return asyncio.Task.current_task(loop=loop)
    except RuntimeError:
        if is_raise:
            raise
        return None


async def wait_other_tasks(loop=None, timeout=None):
    loop = loop or get_loop()
    current = current_task(loop=loop)
    count = 0
    tasks = []
    for task in all_tasks(loop=loop):
        if task is current:
            continue
        tasks.append(task)
    if tasks:
        await asyncio.wait(tasks, timeout=timeout)
    return count


def cancel_other_tasks(loop=None):
    loop = loop or get_loop()
    current = current_task(loop=loop)
    count = 0
    for task in all_tasks(loop=loop):
        if task is current:
            continue
        task.cancel()
        count += 1
    return count
